let tree = null;
let controlDiv;
let controlBar;
let insertForm;
let insertButton;
let searchForm;
let searchButton;
let printInOrderButton;
let printPreOrderButton;
let printPostOrderButton;
let animationSpeedSliderLabel;
let animationSpeedSlider;
let lastMsg = '';
let printOutput = '';

// loader
let canvasHeight = 1024;
let canvasWidth = 1000;
let delay = 1000;

function enableUI() {
  insertForm.removeAttribute('disabled');
  insertButton.removeAttribute('disabled');
  searchForm.removeAttribute('disabled');
  searchButton.removeAttribute('disabled');
  printPreOrderButton.removeAttribute('disabled');
  printInOrderButton.removeAttribute('disabled');
  printPostOrderButton.removeAttribute('disabled');
  animationSpeedSlider.removeAttribute('disabled');
}

function disableUI() {
  insertForm.attribute('disabled', '');
  insertButton.attribute('disabled', '');
  searchForm.attribute('disabled', '');
  searchButton.attribute('disabled', '');
  printPreOrderButton.attribute('disabled', '');
  printInOrderButton.attribute('disabled', '');
  printPostOrderButton.attribute('disabled', '');
  animationSpeedSlider.attribute('disabled', '');
}

function setAnimSpeed() {
  delay = Math.abs(animationSpeedSlider.value());
}

function displayNode(curr) {
  if (curr != null) {
    ellipseMode(CENTER);
    textAlign(CENTER);
    stroke(68, 114, 196);
    strokeWeight(3);
    if (curr.left != null) line(curr.x, curr.y, curr.left.x, curr.left.y);
    if (curr.right != null) line(curr.x, curr.y, curr.right.x, curr.right.y);
    noStroke();
    fill('red');
    if (curr.highlighted) ellipse(curr.x, curr.y, 40, 40);
    fill(169, 209, 142);
    ellipse(curr.x, curr.y, 30, 30);
    fill('black');
    text(curr.data, curr.x, curr.y + 5);
    displayNode(curr.left);
    displayNode(curr.right);
  }
}

async function printPreOrder() {
  disableUI();
  printOutput = "";
  if(tree == null) {
    lastMsg = 'Tree is empty';
  } else {
    await getPreOrder(tree);
    unhighlightAll(tree);
  }
  enableUI();
  return 0;
}

async function printInOrder() {
  disableUI();
  printOutput = "";
  if(tree == null) {
    lastMsg = 'Tree is empty';
  } else {
    await getInOrder(tree);
    unhighlightAll(tree);
  }
  enableUI();
  return 0;
}

async function printPostOrder() {
  disableUI();
  printOutput = "";
  if(tree == null) {
    lastMsg = 'Tree is empty';
  } else {
    await getPostOrder(tree);
    unhighlightAll(tree);
  }
  enableUI();
  return 0;
}

async function insert() {
  value = parseInt(insertForm.value(), 10);
  insertForm.value('');
  if (isNaN(value) === true) return undefined;
  disableUI();
  tree = await pushElement(tree, value, 50, null, 'root'); // push it
  updatePosition(tree); // update all node position
  enableUI()
  return 0;
}

async function find() {
  lastMsg = '';
  printOutput = '';
  value = parseInt(searchForm.value(), 10);
  searchForm.value('');
  if (isNaN(value) === true) return undefined;
  disableUI();
  if(tree == null) {
    lastMsg = 'Tree is empty';
  } else {
    await search(tree, value);
    unhighlightAll(tree);
  }
  enableUI();
  return 0;
}

function addControls(type, name, onClick) {
  let element;
  switch (type) {
    case 'Input':
      element = createInput();
      element.size(60);
      break;
    case 'Button':
      element = createButton(name);
      element.mousePressed(onClick);
      break;
    case 'Slider':
      element = createSlider(-2000, -500, -1000, 20);
      element.mouseReleased(onClick);
      element.touchEnded(onClick);
      break;
    case 'Label':
      element = createP(name);
      element.class('control-label');
      break;
    default: break;
  }
  const tableEntry = createElement('td');
  tableEntry.child(element);
  controlBar.child(tableEntry);
  return element;
}

function setup() {
  // BEGIN VISUALIZATION CONTROLS STUFF
  controlDiv = createDiv();
  controlDiv.parent('mainContent');
  controlDiv.id('controlSection');
  controlBar = createElement('table');
  controlDiv.child(controlBar);
  insertForm = addControls('Input', '', '');
  insertButton = addControls('Button', 'Insert', insert);
  searchForm = addControls('Input', '', '');
  searchButton = addControls('Button', 'Find', find);
  printPreOrderButton = addControls('Button', 'Print Pre Order', printPreOrder);
  printInOrderButton = addControls('Button', 'Print In Order', printInOrder);
  printPostOrderButton = addControls('Button', 'Print Post Order', printPostOrder);
  animationSpeedSliderLabel = addControls('Label', 'Animation Speed:', '');
  animationSpeedSlider = addControls('Slider', '', setAnimSpeed);
  // END VISUALIZATION CONTROLS STUFF

  // SET CANVAS AND TEXT SIZE
  const canvas = createCanvas(canvasHeight, canvasWidth);
  canvas.parent('mainContent');
  textSize(15);
}

function draw() {
  background('white');
  displayNode(tree);
  fill('black');
  textAlign(LEFT);
  text(lastMsg, 30, 50);
  text(printOutput, 30, 70);
}

// custom helper function to deliberately slow down
// the sorting process and make visualization easy
function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}